﻿using CommonEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonDevelop.Scene
{
    public sealed class MenuBox
    {
        #region--私有--

        private static readonly object @lock = new object();
        private static MenuBox MBox;
        private MenuBox() { }
        private static MenuBox GetMBox
        {
            get
            {
                if (MBox == null)
                {
                    lock (@lock)
                    {
                        if (MBox == null)
                        {
                            MBox = new MenuBox();
                        }
                    }
                }
                return MBox;
            }
        }

        private string li_html = "<li {0}>{1}</li>";
        private string li_a_html = "<a href=\"{0}\">{1}{2}{3}</a>";
        private string icon = "<i class=\"fa {0}\"></i>";
        private string title = "<span class=\"nav-label\">{0}</span>";
        private string arrow = "<span class=\"fa arrow\"></span>";
        private string ul_html = "<ul class=\"nav nav-{0}-level collapse\">{1}</ul>";

        private string MakeHtml(List<NavBox> NavBoxLs, string Nid = null)
        {
            if (NavBoxLs == null || NavBoxLs.Count < 1)
                return string.Empty;

            if (string.IsNullOrEmpty(Nid))
            {
                NavBoxLs.First().NActive = true;
            }
            else
            {
                var loop00 = FixedPointFactory.Fix<List<NavBox>, string, string>(f => (BizLs, Id) =>
                {
                    if (string.IsNullOrEmpty(Id))
                        return null;

                    string Pid = null;
                    foreach (var biz in BizLs)
                    {
                        if (biz.NId == Id)
                        {
                            biz.NActive = true;
                            Pid = biz.PId;
                        }
                        else
                        {
                            Pid = f(biz.Children, Id);
                        }
                        //Pid变量钩子是为了保障foreach循环完整
                        if (!string.IsNullOrEmpty(Pid))
                            break;
                    }
                    return Pid;
                });
                var loop01 = FixedPointFactory.Fix<List<NavBox>, string>(f => (BizLs, IdId) =>
                {
                    string PPID = loop00(BizLs, IdId);
                    while (!string.IsNullOrEmpty(PPID))
                    {
                        PPID = loop00(BizLs, PPID);
                    }
                });
                loop01(NavBoxLs, Nid);
            }

            var loop = FixedPointFactory.Fix<List<NavBox>, int, List<Nav>>(f => (Ls, lvl) =>
            {
                List<Nav> NLs = new List<Nav>();
                foreach (var item in Ls)
                {
                    string li_a = string.Format(li_a_html,
                        item.NHref,
                        string.IsNullOrEmpty(item.NIcon) ? "" : string.Format(icon, item.NIcon),
                        lvl == 0 ? string.Format(title, item.NTitle) : item.NTitle,
                        item.Children.Count > 0 ? arrow : "");

                    var n = new Nav { html = li_a, active = item.NActive, level = lvl };
                    NLs.Add(n);
                    n.children = f(item.Children, lvl + 1);
                }
                return NLs;
            });

            var NavLs = loop(NavBoxLs, 0);

            var loop2 = FixedPointFactory.Fix<List<Nav>, string>(f => (NLs) =>
            {
                StringBuilder html = new StringBuilder("");
                foreach (var na in NLs)
                {
                    var A = na.html;
                    if (na.children.Count > 0)
                        A += string.Format(ul_html, na.level > 0 ? "third" : "second", f(na.children));

                    html.Append(string.Format(li_html, na.active ? "class=\"active\"" : "", A));
                }

                return html.ToString();
            });
            return loop2(NavLs);
        }

        [Serializable]
        private class Nav
        {
            public Nav()
            {
                this.children = new List<Nav>();
            }

            public string html { get; set; }
            public bool active { get; set; }
            public int level { get; set; }
            public List<Nav> children { get; set; }
        }

        #endregion

        public static string GetMenuHtml<T>(List<T> Ls, Func<List<T>, List<NavBox>> func, string NId = null)
            where T : class
        {
            if (func == null)
                return string.Empty;

            List<NavBox> NBLs = func(Ls);
            return GetMBox.MakeHtml(NBLs, NId);
        }

        /// <summary>
        /// 输出菜单数据
        /// </summary>        
        public static string GetMenuData(List<SysMenu> tableData, string key = null)
        {
            if (!tableData.IsNotNullOrEmpty())
                return string.Empty;

            var idSelector = FixedPointFactory.Fix<SysMenu, string>(f => (org) =>
            {
                return org.Module_Id;
            });

            var parentIdSelector = FixedPointFactory.Fix<SysMenu, string>(f => (org) =>
            {
                return org.Parent_Id;
            });

            var Maping = FixedPointFactory.Fix<SysMenu, NavBox>(f => (node) =>
            {
                NavBox newNode = new NavBox();
                newNode.NId = node.Module_Id;
                newNode.PId = node.Parent_Id;
                newNode.NTitle = node.Module_Name;
                newNode.NIcon = node.Module_Icon;
                newNode.NHref = node.Module_Action;
                return newNode;
            });

            var NBLS = tableData.GenerateTree(idSelector, parentIdSelector, Maping, x => x.Children, "").ToList();

            var Map = FixedPointFactory.Fix<List<NavBox>, List<NavBox>>(f => (nodeLs) =>
            {
                var result = new List<NavBox>();
                nodeLs.ForEach(node =>
                {
                    NavBox NB = new NavBox();
                    NB.NId = node.NId;
                    NB.PId = node.PId;
                    NB.NSort = node.NSort;
                    NB.NActive = node.NActive;
                    NB.NTitle = node.NTitle;
                    NB.NHref = node.NHref;
                    NB.NIcon = node.NIcon;

                    result.Add(NB);
                    NB.Children = f(node.Children);
                });

                return result;
            });
            return MenuBox.GetMenuHtml<NavBox>(NBLS, Map, key);
        }
    }

    [Serializable]
    public class NavBox
    {
        public NavBox()
        {
            this.Children = new List<NavBox>();
        }

        public string NId { get; set; }
        public string PId { get; set; }
        public int NSort { get; set; }
        public bool NActive { get; set; }
        public string NTitle { get; set; }
        public string NHref { get; set; }
        public string NIcon { get; set; }
        public List<NavBox> Children { get; set; }
    }

    [Serializable]
    public class NavBtn
    {
        public string DomID { get; set; }
        public string DomClass { get; set; }
        public string DomIcon { get; set; }
        public string DomTxt { get; set; }
    }
}
